/* Doug working on file 3/3/12 1:00 pm */
package file;

import static org.junit.Assert.*;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import model.Job;
import model.Park;
import model.PhoneNumber;
import model.PostalAddress;
import model.Role;
import model.User;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import exceptions.UPException;
import file.XMLFacade;

/**
 * XMLFacadeTest class used for testing public
 * and protected methods.
 * 
 * 
 * @author Doug Hutchens
 * @version 1.0
 */
public class XMLFacadeTest {
	
	/**
	 *  Private instance of a static XMLFacade 
	 *  that is used for known testing.
	 */
	
	private XMLFacade my_static_facade;
	
	/**
	 * Private instance of a test XMLFacade
	 * that is written read and manimpulated.
	 */
	
	private XMLFacade my_test_facade;
	
	/**
	 * Private instance of the default XMLFacade
	 * that is written read and manipulated.
	 */
	
	private XMLFacade my_default_facade;
	
	/**
	 * setup() - sets the test environment with dummy
	 * xml files: test_users.xml, test_jobs.xml and 
	 * test_parks.xml.
	 * @throws Exception
	 */
	
	@Before
	public void setUp() throws Exception {
		my_static_facade = new XMLFacade("test_users.xml",
				               	  "test_jobs.xml",
				                  "test_parks.xml");
		
		my_test_facade = new XMLFacade("test_users_save.xml",
                                       "test_jobs_save.xml",
                                       "test_parks_save.xml");
		
		my_default_facade = new XMLFacade();
	}
	
	/**
	 * Testing the loadUsers() method.  The test case
	 * is using a dummy users file named (test_users.xml)
	 * and has a quantity of 49 users.
	 * 
	 * Test Case 1: Verify firstName of user
	 * Test Case 2: Verify collection count is 49.
	 * 
	 * @throws UPException when unable to load users.
	 */

	@Test
	public void testLoadUsers() throws UPException {
		
		Collection<User> users = my_static_facade.loadUsers();

		User test = null;
		for (User u : users) {
			test = u;
			break;
		}
		
		assertEquals("Wayne", test.getFirstName());		
		assertEquals(49, users.size());	
	}
	
	/**
	 * Testing the loadJobs() method. The test case 
	 * is using a dummy jobs file named (test_jobs.xml)
	 * and has a quantity of 3 jobs.
	 * 
	 * Test Case 1: verify name of job.
	 * Test Case 2: verify collection count is 3.
	 * 
	 * @throws UPException when unable to load jobs.
	 */

	@Test
	public void testLoadJobs() throws UPException {
		Collection<Job> jobs = my_static_facade.loadJobs();
		Job test = null;
		
		for (Job j : jobs) {
			test = j;
		}
		assertEquals("SecondJob", test.getName());
		assertEquals(1, jobs.size());
	}
	
	/**
	 * Testing the loadParks() method.  The test case
	 * is using a dummy parks file named (test_parks.xml)
	 * and has a quantity of 38 jobs.
	 * 
	 * Test Case 1: Verify name of park.
	 * Test Case 2: Verify collection count is 38.
	 * 
	 * @throws UPException when unable load parks.
	 */

	@Test
	public void testLoadParks() throws UPException {
		Collection<Park> parks = my_static_facade.loadParks();
		Park test = null;
		
		for (Park p : parks) {
			test = p;
		}
		
		assertEquals("Test Park", test.getName());
		assertEquals(1, parks.size());
	}
	
	/**
	 * Testing the loadConfig() method.  This method
	 * tests the configuration for the application as read
	 * from the configs.xml file.
	 * 
	 * Test Case 1: Verify total maximum job count == 30
	 * Test Case 2: Verify total jobs allowed per week == 5
	 * @throws UPException when unable to load config.
	 */

	@Test
	public void testLoadConfig() throws UPException {
		int [] config = my_static_facade.loadConfig();
		assertEquals(30, config[0]);
		assertEquals(5, config[1]);
	}
	
	/**
	 * Testing the saveUser() method.  This method tests
	 * the ability to save users to an xml file. The original
	 * data will be loaded from a known file (test_users.xml)
	 * and written to a new file (test_users_save.xml).  The 
	 * second file will be manipulated and checked for validity.
	 * 
	 * Test Case 1:  Verify save users.
	 * Test Case 2:  Create a new user, add to file and verify
	 *               contents.
	 * 
	 * @throws UPException 
	 */

	@Test
	public void testSaveUsers()  {
		
		Collection<User> users = new ArrayList<User>();
		
		try {
		
			users = my_static_facade.loadUsers();
			assertEquals(49, users.size()); 
			my_test_facade.saveUsers(users); 
			users.clear();
			users = my_test_facade.loadUsers();
			assertEquals(49, users.size());
			users.clear();
			User user = new User("Jenny",
					             "Jenny",
					             "jenny@jenny.com",
					             new PhoneNumber("5558675309"),
					             Role.VOLUNTEER,
					             "No comments...",
					             new PostalAddress("1 No Way",
					            		           "Manhattan",
					            		           "New York",
					            		           "63210"),
					             false);
			
			users.add(user);
			my_test_facade.saveUsers(users);
			Collection<User> test_users = my_test_facade.loadUsers();
			assertEquals(users, test_users);
			assertEquals(1, test_users.size());
			
			
		} catch (UPException e) {
			System.out.println(e.getMessage());
		}
		
	}
	
	/**
	 * Testing the saveJobs() method.  This tests
	 * the known data from the (test_jobs.xml) file
	 * and saves to a dynamic file test_jobs_save.xml.
	 * 
	 * Test Case 1: Verify save jobs.
	 * Test Case 2: Create a new job, add to file and verify
	 *              contents.
	 * 
	 * @throws UPException 
	 */

	@Test
	public void testSaveJobs()  {
		
		Collection<Job> jobs = new ArrayList<Job>();
		
		try {
			
						
			jobs = my_static_facade.loadJobs();			
			assertEquals(1, jobs.size());
			my_static_facade.saveJobs(jobs);
			jobs.clear();
			jobs = my_static_facade.loadJobs();
			assertEquals(1, jobs.size());
			int [] one = { 1, 2, 3 };
			int [] two = { 3, 2, 1 };
			int [] three = { 3, 3, 3 };
			
			Job test_job = new Job("SecondJob",
					               25,
					               new GregorianCalendar(2012, 1, 1, 15, 59),
					               new GregorianCalendar(2012, 1, 1, 17, 59),
					               one,
					               two,
					               three);
			
		
			Collection<Job> test_jobs = new ArrayList<Job>();
			test_jobs.add(test_job);			
			my_static_facade.saveJobs(test_jobs);
			Collection<Job> file_jobs = my_static_facade.loadJobs();
			assertEquals(1, file_jobs.size());
			assertEquals(test_jobs, file_jobs);
			
		} catch (UPException e) {
			System.out.println(e.getMessage());
		}
		
	}
	
	/**
	 * Testing the saveParks() method.
	 * 
	 * Test Case 1: Verify saveParks();
	 * Test Case 2: Create a new park, add to file and verify
	 *              contents.
	 * @throws UPException 
	 */

	@Test
	public void testSaveParks()  {
		Collection<Park> parks = new ArrayList<Park>();
		
		try {
			
			parks = my_static_facade.loadParks();
			assertEquals(1, parks.size());
			my_static_facade.saveParks(parks);
			parks.clear();
			parks = my_static_facade.loadParks();
			assertEquals(1, parks.size());
			
			Park test_park = new Park("Test Park",
					  				  new PostalAddress("1 No Way",
			            		           "Manhattan",
			            		           "New York",
			            		           "63210"),
			            		      new PhoneNumber("5558675309"),
			            		      6,
			            		      "Cupertino",
			            		      "Cali");
			Collection<Park> test_parks = new ArrayList<Park>();
			test_parks.add(test_park);
			my_static_facade.saveParks(test_parks);
			Collection<Park> file_parks = my_static_facade.loadParks();
			assertEquals(1, file_parks.size());
			assertEquals(test_parks, file_parks);
			
		} catch (UPException e) {
			System.out.println(e.getMessage());
		}
	}
	
	/**
	 * verify that the getDateString() returns the correct
	 * date formatted string.
	 */
	
	@Test
	public void testgetDateString() {
		
		GregorianCalendar date = new GregorianCalendar(2012, 6, 5, 5, 15);
		String expected = "2012-07-05 05:15 AM";
		
		String actual = my_test_facade.getDateString(date);
		assertEquals(expected, actual);
		
	}
	
	/**
	 * Tests the ability to retrieve an attribute from a node name.
	 * @throws UPException
	 */
	
	@Test
	public void testgetAttribute() throws UPException {
		Node test_node = getJobTestNode();
		String expected = "SecondJob";
		String actual = my_test_facade.getAttribute(test_node, "Name");
		assertEquals(expected, actual);				
	}
	
	/**
	 * Tests the ability to change an integer list to a string
	 * used in save methods.
	 */
	
	@Test
	public void testgetStringIds() {
		final List<Integer> test = new ArrayList<Integer>();
		test.add(1);
		test.add(200);
		
		String expected = "1,200,";
		String actual = my_test_facade.getStringIds(test);		
		assertEquals(expected, actual);			
	}
	
	/**
	 * Tests the ability to create a new document and verify
	 * the text content is null.
	 * @throws UPException
	 */
	
	@Test
	public void testgetNewDocument() throws UPException {
		Document document = my_test_facade.getNewDocument();			
		document.createComment("Test");		
		String actual = document.getTextContent();
		assertEquals(null, actual);
	}
	
	@Test (expected=UPException.class)
	public void testGetNewDocException() throws UPException {
		my_test_facade.getDocument("nofileknown");
	}
	
	/**
	 * Tests the getFile with unknown file.  Expected result
	 * is UPException.
	 * 
	 * @throws UPException
	 */
	
	@Test (expected=UPException.class)
	public void testgetFile() throws UPException {
		 my_test_facade.getFile("nofileknown");		
	}
	
	/**
	 * Tests that you can read a boolean attribute from
	 * and XML file.
	 * @throws UPException
	 */
	@Test 
	public void testGetBooleanAttribute() throws UPException {
		
		Node test_node = getUserTestNode();
		boolean actual = my_test_facade.getBooleanAttribute(test_node,
				                                            "isBlackballed");
		
		assertEquals(false, actual);
		
	}
	
	/**
	 * Tests that you can read a date attribute from an 
	 * XML file.
	 * @throws UPException
	 */
	
		
	@Test
	public void testDateAttribute() throws UPException {
		
		Node test_node = getJobTestNode();
		Date actual = my_test_facade.getDateAttribute(test_node,
				                                      "StartTime");
		Calendar g = new GregorianCalendar();
		g.setTime(actual);
		assertEquals(5, Calendar.DATE);
	}
	
	/**
	 * Tests retrieving a GregorianCalendar.
	 * @throws UPException 
	 * @throws ParseException 
	 */	
	
	@Test
	public void testGetGregorianCalendar() throws UPException, ParseException {
		GregorianCalendar result = new GregorianCalendar();
		Node test_node = getJobTestNode();
		Date actual = my_test_facade.getDateAttribute(test_node,
				                                      "StartTime");
		Date expected = null;
		DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd hh:mm aaa");
		expected = dfm.parse("2012-02-01 03:59 PM");	
		GregorianCalendar time = new GregorianCalendar();
		time.setTime(expected);
		result.setTime(actual);
		assertEquals(time, result);		
	}
	
	/**
	 * Tests the integerArrayAttribute.
	 * @throws UPException 
	 */
	
	@Test
	public void testGetIntegerArrayAttribute() throws UPException {
		
		Node test_node = getJobTestNode();
		String actual = my_test_facade.getAttribute(test_node,
				                                  "Light");
		
		String expected = "1,2,3,";
		assertEquals(expected, actual);
		
	}
	
	/**
	 * Tests getting the integer attribute.
	 * @throws UPException
	 */
	
	@Test
	public void testGetIntegerAttribute() throws UPException {
		Node test_node = getJobTestNode();
		String actual = my_test_facade.getAttribute(test_node,
				                                  "HeavySize");
		String expected = "3";
		assertEquals(expected, actual);
	}
	
	/**
	 * Tests getting a job from XML file.
	 * @throws UPException
	 */
	
	@Test
	public void testGetJob() throws UPException {
		Node test_node = getJobTestNode();
		Job actual = my_test_facade.getJob(test_node);
		
		int [] one = { 1, 2, 3 };
		int [] two = { 3, 2, 1 };
		int [] three = { 3, 3, 3 };
		
		Job expected = new Job("SecondJob",
				               25,
				               new GregorianCalendar(2012, 1, 1, 15, 59),
				               new GregorianCalendar(2012, 1, 1, 17, 59),
				               one,
				               two,
				               three);
		
		assertEquals(expected,actual);
	}
	
	/**
	 * check that you can retrieve a nodelist.
	 * @throws UPException
	 */
	
	@Test
	public void testGetNodeList() throws UPException {
		
		NodeList nodes = getNodeList();
		
		assertEquals(99, nodes.getLength());
		
	}
	
	@Test
	public void testGetPark() throws UPException {
		Node test_node = getParkTestNode();
		Park actual = my_test_facade.getPark(test_node);
		
		Park expected = new Park("Test Park",
				                  new PostalAddress("1 No Way",
  		                                            "Manhattan",
  		                                            "New York",
  		                                            "63210"),
  		                          new PhoneNumber("5558675309"),
  		                          6,
  		                          "Cupertino",
  		                          "Cali");
		
		assertEquals(expected, actual);
		
	}	
	
	
	/**
	 * Private method used for testing.
	 * 
	 * @return Node to test.
	 * @throws UPException
	 */
	
	private Node getParkTestNode() throws UPException {
		
		Document document = my_test_facade.getDocument("test_parks.xml");
		NodeList nodes = my_test_facade.getNodeList(document, "ParkList");
		Node test_node = null;
		
		for(int i = 0; i < nodes.getLength(); i++) {
			Node node = nodes.item(i);
			
			if (node.hasAttributes()) {				
				test_node = node;
			}			
		}
		
		return test_node;
		
	}
	/**
	 * Private method used for testing.
	 * 
	 * @return Node to test.
	 * @throws UPException
	 */
	
	private Node getJobTestNode() throws UPException {
		
		Document document = my_test_facade.getDocument("test_jobs.xml");
		NodeList nodes = my_test_facade.getNodeList(document, "JobList");
		Node test_node = null;
		
		for(int i = 0; i < nodes.getLength(); i++) {
			Node node = nodes.item(i);
			
			if (node.hasAttributes()) {				
				test_node = node;
			}			
		}
		
		return test_node;
		
	}
	
	/**
	 * Private method used for testing.
	 * 
	 * @return Node to test.
	 * @throws UPException
	 */
	
	private Node getUserTestNode() throws UPException {
		
		Document document = my_test_facade.getDocument("test_users.xml");
		NodeList nodes = my_test_facade.getNodeList(document, "UserList");
		Node test_node = null;
		
		for(int i = 0; i < nodes.getLength(); i++) {
			Node node = nodes.item(i);
			
			if (node.hasAttributes()) {				
				test_node = node;
			}			
		}
		
		return test_node;
		
	}
	
	/**
	 * Private method for testing on NodeList.
	 * @return
	 * @throws UPException 
	 */
	private NodeList getNodeList() throws UPException {
		Document document = my_test_facade.getDocument("test_users.xml");
		NodeList nodes = my_test_facade.getNodeList(document, "UserList");
		
		
		return nodes;
		
	}
}
